package com.hhwy.components;

import com.hhwy.domain.PressureCheck;
import com.hhwy.service.IPressureCheckService;
import com.hhwy.utils.SpringBeanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 侧压力检测
 */
@Component
public class PressureSocket {

    @Value("${pressure-socket.port}")
    private Integer port;

    @Value("${pressure-socket.enable}")
    private boolean enable;

    private static final Logger log = LoggerFactory.getLogger(PressureSocket.class);

    private static ServerSocket serverSocket = null;

    private static final ThreadPoolExecutor threadpool = new ThreadPoolExecutor(15, 15,
            10L, TimeUnit.SECONDS, new LinkedBlockingQueue<>());

    private static final ConcurrentLinkedQueue<PressureCheck> dataList = new ConcurrentLinkedQueue<>();

    @Bean
    public void startPressureSocket() {
        if (enable) {
            new Thread(() -> {
                try {
                    serverSocket = new ServerSocket(port);
                    log.info("pressure-socket started on port " + port);
                    while (true) {
                        Socket clientSocket = serverSocket.accept();
                        threadpool.execute(new ClientHandler(clientSocket));
                    }
                } catch (IOException e) {
                    log.error("Error starting pressure socket server", e);
                } finally {
                    stop();
                }
            }).start();

            // 启动入库线程
            new Thread(new DataSaver()).start();
        }
    }

    public void stop() {
        try {
            if (serverSocket != null && !serverSocket.isClosed()) {
                serverSocket.close();
            }
        } catch (IOException e) {
            log.error("Error closing server socket", e);
        }
    }

    private static class ClientHandler implements Runnable {
        private final Socket clientSocket;

        public ClientHandler(Socket socket) {
            this.clientSocket = socket;
        }

        @Override
        public void run() {
            try (BufferedInputStream in = new BufferedInputStream(clientSocket.getInputStream())) {
                int r;
                List<Integer> l = new LinkedList<>();
                while ((r = in.read()) != -1) {
                    l.add(r);
                    if (l.size() == 6) {
                        processPressureData(l);
                        l.clear();
                    }
                }
            } catch (IOException e) {
                log.error("Error handling client connection", e);
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException e) {
                    log.error("Error closing client socket", e);
                }
            }
        }

        private void processPressureData(List<Integer> data) {
            PressureCheck pressureCheck = new PressureCheck();

            BigDecimal dataValue = BigDecimal.valueOf(data.get(2)).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            pressureCheck.setData(dataValue.doubleValue());
            pressureCheck.setCreateTime(new Date());
            pressureCheck.setAlermFlag(data.get(0).toString());

            BigDecimal thresholdValue = BigDecimal.valueOf(data.get(4)).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
            pressureCheck.setAlermThreshold(thresholdValue.doubleValue());

            dataList.add(pressureCheck);
            log.info(pressureCheck.toString());
        }
    }

    private static class DataSaver implements Runnable {
        @Override
        public void run() {
            while (true) {
                try {
                    if (dataList.size() > 60) {
                        IPressureCheckService pressureCheckService = SpringBeanUtils.getApplicationContext().getBean(IPressureCheckService.class);
                        pressureCheckService.saveBatch(new ArrayList<>(dataList));
                        dataList.clear();
                    }
                } catch (Exception e) {
                    log.error("Error saving pressure data", e);
                }
                try {
                    Thread.sleep(5000); // 每5秒尝试一次
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error("DataSaver thread interrupted", e);
                }
            }
        }
    }
}
